/* 
 * Example lifted from cppreference
 * https://en.cppreference.com/w/cpp/types/type_index
 * */
#include <cxxomfort/base.hpp>
#include <cxxomfort/typeindex.hpp>
#include <cxxomfort/memory.hpp>
#include <cxxomfort/library/foreach.hpp>
#include <cxxomfort/ostream.hpp>
#include <cxxomfort/library/type_name.hpp>
#include <iostream>
#include <typeinfo>
#if (CXXOMFORT_CXX_STD < 2011 && defined(__GNUC__))
	#include <tr1/unordered_map>
#else
	#include <unordered_map>
#endif
#include <map>
#include <string>
#include <memory>
#include <iomanip>


struct A {
    virtual ~A() {}
};

struct B : A {};
struct C : A {};

int main()
{
    using namespace std;
    cxxomfort::output_info(); cout<< endl;

    cout<< "type_index is: "<< cxxomfort::library::type_name<type_index>()<< endl;

#if (CXXOMFORT_CXX_STD>=2011)
    typedef std::unordered_map<type_index, string> MAP_t;
#else
    typedef std::map<type_index, string> MAP_t;
#endif
	MAP_t type_names;

    type_names[type_index(typeid(int))] = "int";
    type_names[type_index(typeid(double))] = "double";
    type_names[type_index(typeid(A))] = "A";
    type_names[type_index(typeid(B))] = "B";
    type_names[type_index(typeid(C))] = "C";

    int i;
    double d;
    A a;

    // note that we're storing pointer to type A
    std::unique_ptr<A> b(new B);
    std::unique_ptr<A> c(new C);

    cout << "i is " << flush<< type_names[std::type_index(typeid(i))]<< flush<< '\n';
    cout << "d is " << flush<< type_names[std::type_index(typeid(d))] << flush<< '\n';
    cout << "a is " << flush<< type_names[std::type_index(typeid(a))] << flush<< '\n';
    cout << "b is " << type_names[std::type_index(typeid(*b))] << flush<< '\n';
    cout << "c is " << type_names[std::type_index(typeid(*c))] << flush<< '\n';

    typedef pair<type_index const,string> PI;

    CXXO_FOREACH (PI const& p, type_names) {
        cout<< " * "<< p.first.hash_code()<< " = "<< p.second<< " \n";
    }
}
